#include "Camera.h"

#include <math.h>

//-----------------------------------------------------------------------------
// Constructor and Destructor
//-----------------------------------------------------------------------------

Camera::Camera(void)
{
        // uninitialized camera identity
        _camera_id		= -1;
        _camera_name	= "";

        // default setup for uninitialize camera
        _camera_fovy	= 30.0f;
        _camera_ratio	= 1.0f;

        _camera_position_vector		= Vector3D(0.0f, 0.0f, 0.0f);
        _camera_rotation_vector		= Vector3D(0.0f, 0.0f, 0.0f);
        _camera_direction_vector	= Vector3D(0.0f, 0.0f, -1.0f);
        _camera_up_vector		= Vector3D(0.0f, 1.0f, 0.0f);
        _camera_right_vector		= Vector3D(1.0f, 0.0f, 0.0f);

        // camera smooth transition
        EnableSmoothTransition(false);

        _transition_length		= 15;           	// transition interpolation takes x many frames
        _transition_step		= _transition_length;	// transition has been completed

        _initial_position_vector	= _goal_position_vector		= _camera_position_vector;
        _initial_direction_vector	= _goal_direction_vector	= _camera_direction_vector;
        _initial_rotation_vector	= _goal_rotation_vector		= _camera_rotation_vector;
        _initial_up_vector			= _goal_up_vector			= _camera_up_vector;
        _initial_right_vector		= _goal_right_vector		= _camera_right_vector;

}

Camera::~Camera(void)
{
}

//-----------------------------------------------------------------------------
// Basic Camera Maneuvers
//-----------------------------------------------------------------------------

void Camera::rotateX(float degree)
{
        _goal_rotation_vector.setX(_goal_rotation_vector.getX() + degree);

        Vector3D u = _goal_direction_vector * cosf(TO_RADIAN(degree));
        Vector3D v = _goal_up_vector * sinf(TO_RADIAN(degree));

        _goal_direction_vector = u + v;
        _goal_up_vector = Vector3D::CrossProduct(_goal_direction_vector, _goal_right_vector) * -1;

        resetTransition();
}

void Camera::rotateY(float degree)
{
        _goal_rotation_vector.setY(_goal_rotation_vector.getY() + degree);

        Vector3D u = _goal_direction_vector * cosf(TO_RADIAN(degree));
        Vector3D v = _goal_right_vector * sinf(TO_RADIAN(degree));

        _goal_direction_vector = u - v;
        _goal_right_vector = Vector3D::CrossProduct(_goal_direction_vector, _goal_up_vector);

        resetTransition();
}

void Camera::rotateZ(float degree)
{
        _goal_rotation_vector.setZ(_goal_rotation_vector.getZ() + degree);

        Vector3D u = _goal_right_vector * cosf(TO_RADIAN(degree));
        Vector3D v = _goal_up_vector * sinf(TO_RADIAN(degree));

        _goal_right_vector = u + v;
        _goal_up_vector = Vector3D::CrossProduct(_goal_direction_vector, _goal_right_vector) * -1;

        resetTransition();
}

void Camera::forwardTranslate(float distance)
{
        _goal_position_vector = _goal_position_vector + (_goal_direction_vector * -distance);

        resetTransition();
}

void Camera::upTranslate(float distance)
{
        _goal_position_vector = _goal_position_vector + (_goal_up_vector * distance);

        resetTransition();
}

void Camera::rightTranslate(float distance)
{
        _goal_position_vector = _goal_position_vector + (_goal_right_vector * distance);

        resetTransition();
}

//----------------------------------------------------------------------------
// Camera Smooth Transition
//----------------------------------------------------------------------------

void Camera::resetTransition()
{
        _transition_step = 0;

        _initial_position_vector  = _camera_position_vector;
        _initial_direction_vector = _camera_direction_vector;
        _initial_up_vector	  = _camera_up_vector;
        _initial_right_vector	  = _camera_right_vector;
        _initial_rotation_vector  = _camera_rotation_vector;
}

void Camera::updateInterpolation()
{
        if ( _transition_step >= _transition_length )
        {
                _transition_step = _transition_length;

                _initial_position_vector  = _camera_position_vector	 = _goal_position_vector;
                _initial_direction_vector = _camera_direction_vector     = _goal_direction_vector;
                _initial_up_vector	  = _camera_up_vector		 = _goal_up_vector;
                _initial_right_vector	  = _camera_right_vector	 = _goal_right_vector;
                _initial_rotation_vector  = _camera_rotation_vector	 = _goal_rotation_vector;
        }
        else
        {
                _transition_step++;

                float progress = (float) _transition_step / (float) _transition_length;

                _camera_position_vector	 = Vector3D::getLinearCurve(_initial_position_vector,  _goal_position_vector,	progress);
                _camera_direction_vector = Vector3D::getLinearCurve(_initial_direction_vector, _goal_direction_vector,  progress);
                _camera_up_vector	 = Vector3D::getLinearCurve(_initial_up_vector,	 _goal_up_vector,		progress);
                _camera_right_vector	 = Vector3D::getLinearCurve(_initial_right_vector, _goal_right_vector,		progress);
                _camera_rotation_vector	 = Vector3D::getLinearCurve(_initial_rotation_vector,  _goal_rotation_vector,	progress);
        }
}

void Camera::update()
{
        if ( _transition_step < _transition_length )
        {
                if ( IsUsingSmoothTransition() )
                {
                        updateInterpolation();
                }
                else
                {
                        _transition_step = _transition_length;

                        _initial_position_vector  = _camera_position_vector	= _goal_position_vector;
                        _initial_direction_vector = _camera_direction_vector    = _goal_direction_vector;
                        _initial_up_vector	  = _camera_up_vector		= _goal_up_vector;
                        _initial_right_vector	  = _camera_right_vector	= _goal_right_vector;
                        _initial_rotation_vector  = _camera_rotation_vector	= _goal_rotation_vector;
                }
        }
}

void Camera::copyGeometryFrom(const Camera & targetCamera)
{
        _goal_position_vector	= targetCamera._goal_position_vector;
        _goal_direction_vector	= targetCamera._goal_direction_vector;
        _goal_up_vector		= targetCamera._goal_up_vector;
        _goal_right_vector	= targetCamera._goal_right_vector;
        _goal_rotation_vector	= targetCamera._goal_rotation_vector;

        resetTransition();
}
